/**
 * 通用工具函数集合
 * 整理和标准化现有的工具函数
 */

import { v4 as uuidv4 } from 'uuid';
import { REGEX_PATTERNS, MESSAGE_TEMPLATES } from './constants';

/**
 * 数学工具类
 */
export class MathUtils {
    /**
     * 生成指定范围的随机整数
     * @param min 最小值
     * @param max 最大值
     * @returns 随机整数
     */
    static randomInt(min: number, max: number): number {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    /**
     * 生成指定范围的随机浮点数
     * @param min 最小值
     * @param max 最大值
     * @param decimals 小数位数
     * @returns 随机浮点数
     */
    static randomFloat(min: number, max: number, decimals: number = 2): number {
        const random = Math.random() * (max - min) + min;
        return Math.round(random * Math.pow(10, decimals)) / Math.pow(10, decimals);
    }

    /**
     * 加权随机选择
     * @param items 选项数组
     * @param weights 权重数组
     * @returns 选中的项目
     */
    static weightedRandom<T>(items: T[], weights: number[]): T {
        if (items.length !== weights.length) {
            throw new Error('Items and weights arrays must have the same length');
        }

        const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
        let random = Math.random() * totalWeight;

        for (let i = 0; i < items.length; i++) {
            random -= weights[i];
            if (random <= 0) {
                return items[i];
            }
        }

        return items[items.length - 1];
    }

    /**
     * 权重范围随机（从 common.ts 迁移）
     * @param data 范围数据
     * @returns 随机数
     */
    static randomWeight(data: { min: number; max: number }): number {
        const normalizedData = { min: Number(data.min), max: Number(data.max) };
        const range = normalizedData.max - normalizedData.min + 1;
        const weights = Array.from({ length: range }, (_, i) => range - i);
        const totalWeight = weights.reduce((acc, weight) => acc + weight, 0);
        
        let random = Math.random() * totalWeight;
        let chosenNumber = normalizedData.min;
        
        for (let i = 0; i < weights.length; i++) {
            random -= weights[i];
            if (random <= 0) {
                chosenNumber = normalizedData.min + i;
                break;
            }
        }
        
        return chosenNumber;
    }

    /**
     * 限制数值在指定范围内
     * @param value 数值
     * @param min 最小值
     * @param max 最大值
     * @returns 限制后的数值
     */
    static clamp(value: number, min: number, max: number): number {
        return Math.min(Math.max(value, min), max);
    }

    /**
     * 线性插值
     * @param start 起始值
     * @param end 结束值
     * @param t 插值参数 (0-1)
     * @returns 插值结果
     */
    static lerp(start: number, end: number, t: number): number {
        return start + (end - start) * t;
    }
}

/**
 * 字符串工具类
 */
export class StringUtils {
    /**
     * 生成UUID（无短横线）
     * @returns UUID字符串
     */
    static generateUUID(): string {
        return uuidv4().replace(/-/g, '');
    }

    /**
     * 生成标准UUID
     * @returns UUID字符串
     */
    static generateStandardUUID(): string {
        return uuidv4();
    }

    /**
     * 解析指令中的数字（从 common.ts 迁移）
     * @param data 指令字符串
     * @returns 解析结果
     */
    static parseNumbers(data: string): { k1: number; k2: number } {
        const indexMatch = data.match(REGEX_PATTERNS.NUMBER);
        const index = indexMatch ? parseInt(indexMatch[0], 10) : null;
        
        const indexMatch2 = data.match(REGEX_PATTERNS.NUMBER_WITH_SUFFIX);
        const index2 = indexMatch2 ? parseInt(indexMatch2[0].split('q')[1], 10) : null;
        
        return { k1: Math.ceil(index || 0), k2: Math.ceil(index2 || 0) };
    }

    /**
     * 格式化消息模板
     * @param template 消息模板
     * @param params 参数对象
     * @returns 格式化后的消息
     */
    static formatMessage(template: string, params: Record<string, any>): string {
        return template.replace(/\{(\w+)\}/g, (match, key) => {
            return params[key] !== undefined ? String(params[key]) : match;
        });
    }

    /**
     * 截断字符串
     * @param str 原字符串
     * @param length 最大长度
     * @param suffix 后缀
     * @returns 截断后的字符串
     */
    static truncate(str: string, length: number, suffix: string = '...'): string {
        if (str.length <= length) {
            return str;
        }
        return str.substring(0, length - suffix.length) + suffix;
    }

    /**
     * 首字母大写
     * @param str 字符串
     * @returns 首字母大写的字符串
     */
    static capitalize(str: string): string {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }

    /**
     * 驼峰命名转下划线
     * @param str 驼峰命名字符串
     * @returns 下划线命名字符串
     */
    static camelToSnake(str: string): string {
        return str.replace(/([A-Z])/g, '_$1').toLowerCase();
    }

    /**
     * 下划线转驼峰命名
     * @param str 下划线命名字符串
     * @returns 驼峰命名字符串
     */
    static snakeToCamel(str: string): string {
        return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
    }
}

/**
 * 数组工具类
 */
export class ArrayUtils {
    /**
     * 随机打乱数组
     * @param array 原数组
     * @returns 打乱后的新数组
     */
    static shuffle<T>(array: T[]): T[] {
        const result = [...array];
        for (let i = result.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [result[i], result[j]] = [result[j], result[i]];
        }
        return result;
    }

    /**
     * 随机选择数组中的一个元素
     * @param array 数组
     * @returns 随机元素
     */
    static randomPick<T>(array: T[]): T | undefined {
        if (array.length === 0) return undefined;
        return array[Math.floor(Math.random() * array.length)];
    }

    /**
     * 随机选择数组中的多个元素
     * @param array 数组
     * @param count 选择数量
     * @returns 随机元素数组
     */
    static randomPickMultiple<T>(array: T[], count: number): T[] {
        if (count >= array.length) return [...array];
        
        const shuffled = this.shuffle(array);
        return shuffled.slice(0, count);
    }

    /**
     * 数组去重
     * @param array 数组
     * @param keyFn 键函数（可选）
     * @returns 去重后的数组
     */
    static unique<T>(array: T[], keyFn?: (item: T) => any): T[] {
        if (!keyFn) {
            return [...new Set(array)];
        }
        
        const seen = new Set();
        return array.filter(item => {
            const key = keyFn(item);
            if (seen.has(key)) {
                return false;
            }
            seen.add(key);
            return true;
        });
    }

    /**
     * 数组分组
     * @param array 数组
     * @param keyFn 分组键函数
     * @returns 分组后的对象
     */
    static groupBy<T>(array: T[], keyFn: (item: T) => string): Record<string, T[]> {
        return array.reduce((groups, item) => {
            const key = keyFn(item);
            if (!groups[key]) {
                groups[key] = [];
            }
            groups[key].push(item);
            return groups;
        }, {} as Record<string, T[]>);
    }

    /**
     * 数组分页
     * @param array 数组
     * @param page 页码（从1开始）
     * @param pageSize 页大小
     * @returns 分页结果
     */
    static paginate<T>(array: T[], page: number, pageSize: number): {
        items: T[];
        total: number;
        page: number;
        pageSize: number;
        totalPages: number;
        hasNext: boolean;
        hasPrev: boolean;
    } {
        const startIndex = (page - 1) * pageSize;
        const endIndex = startIndex + pageSize;
        const items = array.slice(startIndex, endIndex);
        const total = array.length;
        const totalPages = Math.ceil(total / pageSize);
        
        return {
            items,
            total,
            page,
            pageSize,
            totalPages,
            hasNext: page < totalPages,
            hasPrev: page > 1
        };
    }
}

/**
 * 对象工具类
 */
export class ObjectUtils {
    /**
     * 深度克隆对象
     * @param obj 原对象
     * @returns 克隆后的对象
     */
    static deepClone<T>(obj: T): T {
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }
        
        if (obj instanceof Date) {
            return new Date(obj.getTime()) as any;
        }
        
        if (obj instanceof Array) {
            return obj.map(item => this.deepClone(item)) as any;
        }
        
        if (typeof obj === 'object') {
            const cloned = {} as any;
            for (const key in obj) {
                if (obj.hasOwnProperty(key)) {
                    cloned[key] = this.deepClone(obj[key]);
                }
            }
            return cloned;
        }
        
        return obj;
    }

    /**
     * 深度合并对象
     * @param target 目标对象
     * @param sources 源对象
     * @returns 合并后的对象
     */
    static deepMerge<T extends object>(target: T, ...sources: Partial<T>[]): T {
        if (!sources.length) return target;
        const source = sources.shift();

        if (this.isObject(target) && this.isObject(source)) {
            for (const key in source) {
                if (this.isObject(source[key])) {
                    if (!target[key as keyof T]) {
                        Object.assign(target as any, { [key]: {} });
                    }
                    this.deepMerge(target[key as keyof T] as any, source[key] as any);
                } else {
                    Object.assign(target as any, { [key]: source[key] });
                }
            }
        }

        return this.deepMerge(target, ...sources);
    }

    /**
     * 判断是否为对象
     * @param item 项目
     * @returns 是否为对象
     */
    private static isObject(item: any): boolean {
        return item && typeof item === 'object' && !Array.isArray(item);
    }

    /**
     * 获取嵌套属性值
     * @param obj 对象
     * @param path 属性路径
     * @param defaultValue 默认值
     * @returns 属性值
     */
    static get<T>(obj: any, path: string, defaultValue?: T): T {
        const keys = path.split('.');
        let result = obj;
        
        for (const key of keys) {
            if (result == null || typeof result !== 'object') {
                return defaultValue as T;
            }
            result = result[key];
        }
        
        return result !== undefined ? result : defaultValue;
    }

    /**
     * 设置嵌套属性值
     * @param obj 对象
     * @param path 属性路径
     * @param value 值
     */
    static set(obj: any, path: string, value: any): void {
        const keys = path.split('.');
        const lastKey = keys.pop()!;
        let current = obj;
        
        for (const key of keys) {
            if (current[key] == null || typeof current[key] !== 'object') {
                current[key] = {};
            }
            current = current[key];
        }
        
        current[lastKey] = value;
    }
}

/**
 * 时间工具类
 */
export class TimeUtils {
    /**
     * 获取当前时间戳（毫秒）
     * @returns 时间戳
     */
    static now(): number {
        return Date.now();
    }

    /**
     * 格式化时间
     * @param date 日期对象或时间戳
     * @param format 格式字符串
     * @returns 格式化后的时间字符串
     */
    static format(date: Date | number, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
        const d = typeof date === 'number' ? new Date(date) : date;
        
        const year = d.getFullYear();
        const month = String(d.getMonth() + 1).padStart(2, '0');
        const day = String(d.getDate()).padStart(2, '0');
        const hours = String(d.getHours()).padStart(2, '0');
        const minutes = String(d.getMinutes()).padStart(2, '0');
        const seconds = String(d.getSeconds()).padStart(2, '0');
        
        return format
            .replace('YYYY', String(year))
            .replace('MM', month)
            .replace('DD', day)
            .replace('HH', hours)
            .replace('mm', minutes)
            .replace('ss', seconds);
    }

    /**
     * 获取相对时间描述
     * @param date 日期对象或时间戳
     * @returns 相对时间描述
     */
    static getRelativeTime(date: Date | number): string {
        const now = Date.now();
        const target = typeof date === 'number' ? date : date.getTime();
        const diff = now - target;
        
        const minute = 60 * 1000;
        const hour = 60 * minute;
        const day = 24 * hour;
        const week = 7 * day;
        const month = 30 * day;
        const year = 365 * day;
        
        if (diff < minute) return '刚刚';
        if (diff < hour) return `${Math.floor(diff / minute)}分钟前`;
        if (diff < day) return `${Math.floor(diff / hour)}小时前`;
        if (diff < week) return `${Math.floor(diff / day)}天前`;
        if (diff < month) return `${Math.floor(diff / week)}周前`;
        if (diff < year) return `${Math.floor(diff / month)}个月前`;
        return `${Math.floor(diff / year)}年前`;
    }

    /**
     * 检查是否为今天
     * @param date 日期对象或时间戳
     * @returns 是否为今天
     */
    static isToday(date: Date | number): boolean {
        const target = typeof date === 'number' ? new Date(date) : date;
        const today = new Date();
        
        return target.getDate() === today.getDate() &&
               target.getMonth() === today.getMonth() &&
               target.getFullYear() === today.getFullYear();
    }
}

/**
 * 验证工具类
 */
export class ValidationUtils {
    /**
     * 验证用户名
     * @param username 用户名
     * @returns 是否有效
     */
    static isValidUsername(username: string): boolean {
        return REGEX_PATTERNS.USERNAME.test(username);
    }

    /**
     * 验证密码
     * @param password 密码
     * @returns 是否有效
     */
    static isValidPassword(password: string): boolean {
        return REGEX_PATTERNS.PASSWORD.test(password);
    }

    /**
     * 验证邮箱
     * @param email 邮箱
     * @returns 是否有效
     */
    static isValidEmail(email: string): boolean {
        return REGEX_PATTERNS.EMAIL.test(email);
    }

    /**
     * 验证UUID
     * @param uuid UUID字符串
     * @returns 是否有效
     */
    static isValidUUID(uuid: string): boolean {
        return REGEX_PATTERNS.UUID.test(uuid);
    }

    /**
     * 验证IP地址
     * @param ip IP地址
     * @returns 是否有效
     */
    static isValidIP(ip: string): boolean {
        return REGEX_PATTERNS.IP_ADDRESS.test(ip);
    }
}
